package com.example.palette.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;

import androidx.annotation.Nullable;

import com.example.palette.R;


public class ClockView extends View {
    private static final String DEFAULT_CENRER_LEFT_TEXT = "还剩";
    private static final String DEFAULT_CENRER_RIGHT_TEXT = "分钟";
    private float mRingStartDegree;
    private float mCornerStartDegree;
    private int mScreenShortBorder;
    private int mBorder;
    private float mRingWidth;
    private int mRingHintColor;
    private int mRingRealColor;
    private int mCurrentProgress;
    private int mTotalProgress;
    private float mScaleSpace;
    private int mScaleTextColor;
    private float mShortScaleSize;
    private int mShortScaleColor;
    private float mLongScaleSize;
    private int mLongScaleColor;
    private float mScaleTimeTextSize;
    private float mCenterTimeTextSize;
    private int mLeftOrRigntTextColor;
    private int mCenterTextColor;
    private float mScaleWidth;
    private boolean mDrawCorner;
    private Paint mPaint;
    private String mMaxTime;
    private String mHalfTime;
    private String mRemainTime;
    private String mRemainTimeLeft;
    private String mRemainTimeRight;
    private Rect mTextRect;

    public ClockView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        ViewGroup.LayoutParams layoutParams = getLayoutParams();
        int width = layoutParams.width;
        int height = layoutParams.height;
        if (width == 0 || height == 0) {
            throw new RuntimeException("you can not set layout_width or layout_height value = 0");
        }
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);
        if (!(widthMode == MeasureSpec.EXACTLY) || !(heightMode == MeasureSpec.EXACTLY)) {
            throw new RuntimeException("you can not set layout_width or layout_height value = wrap_content");
        }
        int borderSize = Math.min(Math.min(widthSize, heightSize), mScreenShortBorder);
        setMeasuredDimension(borderSize, borderSize);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBorder = w;
        mPaint.setTextSize(mScaleTimeTextSize);
        mPaint.getTextBounds(mMaxTime, 0, mMaxTime.length(), mTextRect);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        drawRing(canvas);
        if (mDrawCorner) {
            drawCorner(canvas);
        }
        drawScale(canvas);
        drawScaleInfo(canvas);
        drawCenterInfo(canvas);
    }

    private void init(Context context, AttributeSet attrs) {
        mScreenShortBorder = getScreenShortBorder(context);
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ClockView);
        mRingStartDegree = typedArray.getFloat(R.styleable.ClockView_cv_ringStartDegree, -90f);
        mCornerStartDegree = mRingStartDegree > 0 ? Math.abs(360 - mRingStartDegree) : Math.abs(mRingStartDegree);
        mRingWidth = typedArray.getDimension(R.styleable.ClockView_cv_ringWidth, dp2px(context, 20));
        mRingHintColor = typedArray.getColor(R.styleable.ClockView_cv_ringHintColor, Color.GRAY);
        mRingRealColor = typedArray.getColor(R.styleable.ClockView_cv_ringDrawColor, Color.BLUE);
        mTotalProgress = typedArray.getInteger(R.styleable.ClockView_cv_totalProgress, 30);
        mScaleSpace = typedArray.getDimension(R.styleable.ClockView_cv_scaleSpace, dp2px(context, 5));
        mShortScaleSize = typedArray.getDimension(R.styleable.ClockView_cv_shortScaleLength, dp2px(context, 15));
        mLongScaleSize = typedArray.getDimension(R.styleable.ClockView_cv_longScaleLength, dp2px(context, 30));
        mScaleTimeTextSize = typedArray.getDimension(R.styleable.ClockView_cv_scaleTextSize, sp2px(context, 14));
        mCenterTimeTextSize = typedArray.getDimension(R.styleable.ClockView_cv_centerTextSize, sp2px(context, 28));
        mShortScaleColor = typedArray.getColor(R.styleable.ClockView_cv_shortScaleColor, Color.GRAY);
        mLongScaleColor = typedArray.getColor(R.styleable.ClockView_cv_longScaleColor, Color.BLACK);
        mScaleTextColor = typedArray.getColor(R.styleable.ClockView_cv_scaleTextColor, Color.BLACK);
        mRemainTimeLeft = typedArray.getString(R.styleable.ClockView_cv_centerLeftText) == null ? DEFAULT_CENRER_LEFT_TEXT : typedArray.getString(R.styleable.ClockView_cv_centerLeftText);
        mRemainTimeRight = typedArray.getString(R.styleable.ClockView_cv_centerRightText) == null ? DEFAULT_CENRER_RIGHT_TEXT : typedArray.getString(R.styleable.ClockView_cv_centerRightText);
        mLeftOrRigntTextColor = typedArray.getColor(R.styleable.ClockView_cv_leftOrRigntTextColor, Color.BLACK);
        mCenterTextColor = typedArray.getColor(R.styleable.ClockView_cv_centerTextColor, Color.BLUE);
        mScaleWidth = typedArray.getDimension(R.styleable.ClockView_cv_scaleWidth, dp2px(context, 1));
        mDrawCorner = typedArray.getBoolean(R.styleable.ClockView_cv_drawCorner, true);
        typedArray.recycle();
        mTextRect = new Rect();
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStrokeWidth(mRingWidth);
        mMaxTime = String.valueOf(mTotalProgress);
        mHalfTime = String.valueOf(mTotalProgress / 2);
        mRemainTime = mMaxTime;
    }

    private int getScreenShortBorder(Context context) {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
        if (displayMetrics.widthPixels <= displayMetrics.heightPixels) {
            return displayMetrics.widthPixels;
        } else {
            return displayMetrics.heightPixels;
        }
    }

    private void drawRing(Canvas canvas) {
        canvas.save();
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mRingWidth);
        mPaint.setColor(mRingHintColor);
        float halfRingWidth = mRingWidth / 2;
        canvas.drawArc(halfRingWidth, halfRingWidth, mBorder - halfRingWidth, mBorder - halfRingWidth, 0, 360, false, mPaint);
        if (mCurrentProgress > 0) {
            mPaint.setColor(mRingRealColor);
            float degree = ((float) mCurrentProgress / mTotalProgress) * 360;
            canvas.drawArc(halfRingWidth, halfRingWidth, mBorder - halfRingWidth, mBorder - halfRingWidth, mRingStartDegree, degree, false, mPaint);
        }
        canvas.restore();
    }

    private void drawCorner(Canvas canvas) {
        if (mCurrentProgress > 0) {
            canvas.save();
            mPaint.setStyle(Paint.Style.FILL);
            mPaint.setStrokeWidth(0);
            float degree = ((float) mCurrentProgress / mTotalProgress) * 360;
            canvas.rotate(mCornerStartDegree, mBorder / 2, mBorder / 2);
            canvas.drawCircle(mRingWidth / 2, mBorder / 2, mRingWidth / 2, mPaint);
            canvas.rotate(degree, mBorder / 2, mBorder / 2);
            canvas.drawCircle(mRingWidth / 2, mBorder / 2, mRingWidth / 2, mPaint);
            canvas.restore();
        }
    }

    private void drawScale(Canvas canvas) {
        canvas.save();
        mPaint.setStrokeWidth(mScaleWidth);
        mPaint.setColor(mRingHintColor);
        canvas.translate(getWidth() / 2, getHeight() / 2);
        for (int i = 1; i <= 60; i++) {
            if ((i - 1) % 5 == 0) {
                mPaint.setColor(mLongScaleColor);
                canvas.drawLine(0, mBorder / 2 - mRingWidth - mScaleSpace, 0, mBorder / 2 - mRingWidth - mScaleSpace - mLongScaleSize, mPaint);
            } else {
                mPaint.setColor(mShortScaleColor);
                canvas.drawLine(0, mBorder / 2 - mRingWidth - mScaleSpace, 0, mBorder / 2 - mRingWidth - mScaleSpace - mShortScaleSize, mPaint);
            }
            canvas.rotate(6f);
        }
        canvas.restore();
    }

    private void drawScaleInfo(Canvas canvas) {
        canvas.save();
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mScaleTextColor);
        canvas.translate(getWidth() / 2, 0);
        canvas.drawText(mMaxTime, -mTextRect.width() / 2, mTextRect.height() + mRingWidth + mScaleSpace * 2 + mLongScaleSize, mPaint);
        canvas.drawText(mHalfTime, -mTextRect.width() / 2, mBorder - (mRingWidth + mScaleSpace * 2 + mLongScaleSize), mPaint);
        canvas.restore();
    }

    private void drawCenterInfo(Canvas canvas) {
        canvas.save();
        mPaint.setTextSize(mCenterTimeTextSize);
        mPaint.getTextBounds(mRemainTime, 0, mRemainTime.length(), mTextRect);
        mPaint.setColor(mCenterTextColor);
        int remainTimeHalfWidth = mTextRect.width() / 2;
        int remainTimeHalfHeight = mTextRect.centerY() / 2;
        canvas.drawText(mRemainTime, mBorder / 2 - remainTimeHalfWidth, mBorder / 2 - remainTimeHalfHeight, mPaint);
        mPaint.setTextSize(mScaleTimeTextSize);
        mPaint.getTextBounds(mRemainTimeLeft, 0, mRemainTimeLeft.length(), mTextRect);
        mPaint.setColor(mLeftOrRigntTextColor);
        canvas.drawText(mRemainTimeLeft, mBorder / 2 - remainTimeHalfWidth - mTextRect.width() - mScaleSpace, mBorder / 2 - mTextRect.centerY() / 2, mPaint);
        mPaint.getTextBounds(mRemainTimeRight, 0, mRemainTimeRight.length(), mTextRect);
        canvas.drawText(mRemainTimeRight, mBorder / 2 + remainTimeHalfWidth + mScaleSpace, mBorder / 2 - mTextRect.centerY() / 2, mPaint);
        canvas.restore();
    }

    private int dp2px(Context context, float dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());
    }

    private int sp2px(Context context, float sp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());
    }

    public void setProgress(int progress) {
        if (progress < 0) {
            progress = 0;
        }
        if (progress > mTotalProgress) {
            progress = mTotalProgress;
        }
        mCurrentProgress = progress;
        mRemainTime = String.valueOf(mTotalProgress - mCurrentProgress);
        postInvalidate();
    }

    public void resetProgress() {
        mCurrentProgress = 0;
        mRemainTime = String.valueOf(mTotalProgress - mCurrentProgress);
        postInvalidate();
    }
}
